package com.hucsmn.xcopy;

import java.io.*;
import java.nio.file.AccessDeniedException;
import java.util.*;

/**
 * 文件树。
 */
class FileTree {
    private File root;
    private List<File> dirs;
    private List<File> files;

    /**
     * 列举目录下的所有文件。
     *
     * @param root 根文件夹位置。
     * @throws IOException 根目录不存在或文件夹无法访问。
     */
    public FileTree(File root) throws IOException {
        setRoot(root);
    }

    /**
     * 获取根文件夹位置。
     *
     * @return 根文件夹位置。
     */
    public File getRoot() {
        return root;
    }

    /**
     * 更改目录，并列举目录下的所有文件。
     *
     * @param root 根文件夹位置。
     * @throws IOException 根目录不存在或文件夹无法访问。
     */
    private void setRoot(File root) throws IOException {
        if (root == null) {
            throw new NullPointerException();
        }
        this.dirs = new ArrayList<>();
        this.files = new ArrayList<>();
        this.root = root.getCanonicalFile();
        list(root);
    }

    /**
     * 将指定目录下的文件列举出来，追加到目录树的记录中。
     *
     * @param root 目录或文件。
     * @throws IOException 文件或目录不存在，或文件夹无法访问。
     */
    private void list(File root) throws IOException {
        if (!root.exists()) {
            throw new FileNotFoundException(root.getPath());
        }
        if (!root.isDirectory()) {
            files.add(root);
            return;
        }

        dirs.add(root);
        File[] files = root.listFiles();
        if (files == null) {
            throw new AccessDeniedException(root.getPath());
        }
        for (File file : files) {
            list(file);
        }
    }

    /**
     * 按深度优先顺序列举全部文件夹。
     *
     * @return 文件夹列表。
     */
    public List<File> dirs() {
        return dirs;
    }

    /**
     * 按深度优先顺序列举全部文件。
     *
     * @return 文件列表。
     */
    public List<File> files() {
        return files;
    }
}
